import { existsSync, mkdir, mkdirSync, readFileSync, writeFileSync } from "fs";
import { readJsonSync } from "fs-extra";
import path from "path";
import { AssetInfo } from "../../@types/packages/asset-db/@types/public";
import { CACHE_DIR } from "../const";
import Export from "./01_ExtractAssetInfo";

function onAssetChange(uuid: string, assetInfo: AssetInfo) {
    if (assetInfo.type == 'cc.Prefab' || assetInfo.type == 'cc.SceneAsset') {
        let {path, json} = getCacheJson(uuid, 'A_S');
        let data = json[uuid]; // 如果是导出过的资源 刷新时自动刷新脚本
        if (data) {
            Export.exportSingleAsset(assetInfo);
        }
    }
    else if (assetInfo.type == 'cc.Script') {
        let {path, json} = getCacheJson(uuid, 'S_A');
        let assetUUID = json[uuid];
        if (assetUUID) { // 为了脚本移动时，刷新Cache信息
            addMap_A_S(assetUUID, assetInfo)
        }
    }
}

function onAssetDelete(uuid: string, assetInfo: AssetInfo) {
    if (assetInfo.type == 'cc.Prefab' || assetInfo.type == 'cc.SceneAsset') {
        let scriptUUID = del_A_S(uuid);
        if (scriptUUID) {
            del_S_A(scriptUUID);
        }
    }
    else if (assetInfo.type == 'cc.Script') {
        let assetUUID = del_S_A(uuid);
        if (assetUUID) {
            del_A_S(assetUUID);
        }
    }
}

/**
 * 查找资源的导出脚本缓存数据
 * @param assetUUID Prefab 或者 Scene的uuid
 */
function getAssetCache(assetUUID: string) {
    let {path, json} = getCacheJson(assetUUID, 'A_S');
    return json[assetUUID];
}

async function addCacheWithUUID(scriptUUID: string, assetUUID: string) {
    del_S_A(scriptUUID);
    del_A_S(assetUUID);
    let assInfo = await Editor.Message.request('asset-db', 'query-asset-info', assetUUID);
    let srcInfo = await Editor.Message.request('asset-db', 'query-asset-info', scriptUUID);
    if (srcInfo && assInfo) {
        addCache(srcInfo, assInfo);
    }
}

/** 新增缓存数据 */
function addCache(scriptInfo: AssetInfo, assetInfo: AssetInfo) {
    addMap_S_A(scriptInfo.uuid, assetInfo.uuid);
    addMap_A_S(assetInfo.uuid, scriptInfo);
}

/** 添加脚本uuid 和 asset uuid的映射 */
function addMap_S_A(scriptUUID: string, assetUUID: string) {
    let {path, json} = getCacheJson(scriptUUID, 'S_A');
    json[scriptUUID] = assetUUID;
    writeFileSync(path, JSON.stringify(json));
}

/** 添加asset uuid 和 脚本信息的映射 */
function addMap_A_S(assetUUID: string, scriptInfo: AssetInfo) {
    let {path, json} = getCacheJson(assetUUID, 'A_S');
    let data = {
        uuid: scriptInfo.uuid,
        url: scriptInfo.url
    }
    json[assetUUID] = data
    writeFileSync(path, JSON.stringify(json));
}

/** 删除 s_a 映射 */
function del_S_A(scriptUUID: string): string | null {
    let {path, json} = getCacheJson(scriptUUID, 'S_A');
    let assetUUID = json[scriptUUID]
    delete json[scriptUUID];
    writeFileSync(path, JSON.stringify(json));
    return assetUUID;
}

/** 删除 a_s 映射 */
function del_A_S(assetUUID: string): string | null {
    let {path, json} = getCacheJson(assetUUID, 'A_S');
    let obj = json[assetUUID]
    delete json[assetUUID];
    writeFileSync(path, JSON.stringify(json));
    return obj?.uuid;
}

function getCacheJson(uuid: string, type: 'A_S'|'S_A') {
    if (!existsSync(CACHE_DIR)) {
        mkdirSync(CACHE_DIR);
    }
    let subDir = uuid.slice(0, 2);
    let dir = path.join(CACHE_DIR, subDir);
    if (!existsSync(dir)) {
        mkdirSync(dir);
    }
    let jsonFile = path.join(dir, `${type}.json`);
    let obj;
    if (!existsSync(jsonFile)) {
        obj = {};
    }
    else {
        obj = readJsonSync(jsonFile);
    }
    return {
        path: jsonFile,
        json: obj
    }
}

export default {
    onAssetChange,
    onAssetDelete,
    addCacheWithUUID,
    addCache,
    getAssetCache,
}

type AssetScriptCache = {
    [key: string]: {
        uuid: string,
        url: string,
    }
}
